개요
Timefit 예약 관리 시스템의 예약 생성, 조회, 수정, 취소 및 상태 관리를 위한 API입니다. 고객의 예약 신청부터 업체의 예약 승인/거절, 완료 처리까지 전체 예약 라이프사이클을 관리합니다.
API 목록
구분 | API 명 | 설명 |
---|---|---|
고객 예약 | 예약 신청 | 고객이 업체에 예약을 신청합니다 |
고객 예약 | 내 예약 목록 조회 | 고객이 자신의 예약 목록을 조회합니다 |
고객 예약 | 예약 상세 조회 | 특정 예약의 상세 정보를 조회합니다 |
고객 예약 | 예약 수정 | 예약 정보를 수정합니다 |
고객 예약 | 예약 취소 | 예약을 취소합니다 |
업체 예약 | 받은 예약 신청 조회 | 업체가 받은 예약 신청을 조회합니다 |
업체 예약 | 예약 승인/거절 | 예약 신청을 승인하거나 거절합니다 |
업체 예약 | 예약 상태 변경 | 예약을 완료 또는 노쇼 처리합니다 |
업체 예약 | 예약 캘린더 조회 | 업체의 예약 현황을 캘린더 형태로 조회합니다 |
공통 | 업체 조회 (고객용) | 고객이 예약하고자 하는 업체 정보를 조회합니다 |
1. 예약 신청
고객이 업체에 예약을 신청합니다.
Request
Request Syntax
curl -X POST https://{SERVER_URL}/api/reservations \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"availableSlotId": "770e8400-e29b-41d4-a716-446655440002",
"reservationDate": "2024-06-15",
"reservationTime": "14:00",
"durationMinutes": 60,
"selectedOptions": [
{
"optionId": "880e8400-e29b-41d4-a716-446655440003",
"optionName": "커트",
"price": 25000
}
],
"notes": "앞머리 짧게 잘라주세요",
"customerName": "김고객",
"customerPhone": "01098765432"
}'
메서드 | 요청 URL |
---|---|
POST | https://{SERVER_URL}/api/reservations |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Authorization | String | 필수 | Bearer |
Content-Type | String | 필수 | application/json |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
businessId | string | Y | 업체 ID (UUID) | 660e8400-e29b-41d4... | UUID 형식 |
availableSlotId | string | Y | 예약 가능 슬롯 ID | 770e8400-e29b-41d4... | UUID 형식 |
reservationDate | string | Y | 예약 날짜 | 2024-06-15 | YYYY-MM-DD 형식, 오늘 이후 |
reservationTime | string | Y | 예약 시간 | 14:00 | HH:mm 형식 |
durationMinutes | integer | Y | 예약 지속 시간(분) | 60 | 15분 단위, 최소 15분 |
selectedOptions | array | N | 선택한 서비스 옵션 | [] | 배열 |
selectedOptions[].optionId | string | Y | 옵션 ID | 880e8400-e29b-41d4... | UUID 형식 |
selectedOptions[].optionName | string | Y | 옵션명 | 커트 | - |
selectedOptions[].price | integer | Y | 옵션 가격 | 25000 | 0 이상 |
notes | string | N | 요청사항 | 앞머리 짧게 잘라주세요 | 500자 이하 |
customerName | string | Y | 고객 이름 | 김고객 | 2-50자 |
customerPhone | string | Y | 고객 연락처 | 01098765432 | 01X-XXXX-XXXX 형식 |
Response
Response Syntax (201 Created)
{
"success": true,
"message": "예약이 완료되었습니다",
"data": {
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"reservationNumber": "RES-20240615-001",
"status": "PENDING",
"businessInfo": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678"
},
"reservationDetails": {
"date": "2024-06-15",
"time": "14:00",
"durationMinutes": 60,
"selectedOptions": [
{
"optionId": "880e8400-e29b-41d4-a716-446655440003",
"optionName": "커트",
"price": 25000
}
],
"totalPrice": 25000,
"notes": "앞머리 짧게 잘라주세요"
},
"customerInfo": {
"customerId": "440e8400-e29b-41d4-a716-446655440006",
"customerName": "김고객",
"customerPhone": "01098765432"
},
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
}
}
Response Elements
필드 | 타입 | 필수여부 | 설명 |
---|---|---|---|
reservationId | string | 필수 | 예약 ID (UUID) |
reservationNumber | string | 필수 | 예약 번호 |
status | string | 필수 | 예약 상태 (PENDING, CONFIRMED, COMPLETED, CANCELLED, NO_SHOW) |
businessInfo | object | 필수 | 업체 정보 |
reservationDetails | object | 필수 | 예약 상세 정보 |
customerInfo | object | 필수 | 고객 정보 |
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
BUSINESS_NOT_FOUND | 404 | "업체 정보를 찾을 수 없습니다" | 존재하지 않는 업체 |
SLOT_NOT_AVAILABLE | 409 | "해당 시간대는 예약할 수 없습니다" | 슬롯 예약 불가 |
SLOT_ALREADY_BOOKED | 409 | "이미 예약된 시간대입니다" | 슬롯 중복 예약 |
VALIDATION_ERROR | 400 | "입력값이 올바르지 않습니다" | 필드 검증 실패 |
BUSINESS_CLOSED | 400 | "해당 날짜는 영업일이 아닙니다" | 영업시간 외 예약 |
2. 내 예약 목록 조회
고객이 자신의 예약 목록을 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/reservations?status=PENDING&page=1&size=10 \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/reservations |
Query Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 | 기본값 |
---|---|---|---|---|---|
status | string | N | 예약 상태 필터 | PENDING, CONFIRMED | 전체 |
startDate | string | N | 조회 시작 날짜 | 2024-06-01 | 30일 전 |
endDate | string | N | 조회 종료 날짜 | 2024-06-30 | 오늘 |
businessId | string | N | 특정 업체 필터 | 660e8400-e29b... | 전체 |
page | integer | N | 페이지 번호 | 1 | 1 |
size | integer | N | 페이지 크기 | 10 | 20 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약 목록 조회가 완료되었습니다",
"data": {
"reservations": [
{
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"reservationNumber": "RES-20240615-001",
"status": "CONFIRMED",
"businessInfo": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"logoUrl": "<https://example.com/logo.jpg>"
},
"reservationDetails": {
"date": "2024-06-15",
"time": "14:00",
"durationMinutes": 60,
"selectedOptions": [
{
"optionName": "커트",
"price": 25000
}
],
"totalPrice": 25000
},
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T13:00:00Z"
}
],
"pagination": {
"currentPage": 1,
"totalPages": 5,
"totalElements": 48,
"size": 10,
"hasNext": true,
"hasPrevious": false
}
}
}
3. 예약 상세 조회
특정 예약의 상세 정보를 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/reservations/{reservationId} \\
-H "Authorization: Bearer {accessToken}"
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
reservationId | string | Y | 예약 ID (UUID) | 990e8400-e29b-41d4... |
Response
Response Syntax (200 OK)
예약 신청과 동일한 응답 구조에 상태 변경 이력이 추가됩니다.
{
"success": true,
"message": "예약 상세 조회가 완료되었습니다",
"data": {
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"reservationNumber": "RES-20240615-001",
"status": "CONFIRMED",
"businessInfo": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678",
"logoUrl": "<https://example.com/logo.jpg>"
},
"reservationDetails": {
"date": "2024-06-15",
"time": "14:00",
"durationMinutes": 60,
"selectedOptions": [
{
"optionId": "880e8400-e29b-41d4-a716-446655440003",
"optionName": "커트",
"price": 25000
}
],
"totalPrice": 25000,
"notes": "앞머리 짧게 잘라주세요"
},
"customerInfo": {
"customerId": "440e8400-e29b-41d4-a716-446655440006",
"customerName": "김고객",
"customerPhone": "01098765432"
},
"statusHistory": [
{
"status": "PENDING",
"reason": "예약이 신청되었습니다",
"changedAt": "2024-06-07T12:30:00Z",
"changedBy": "customer"
},
{
"status": "CONFIRMED",
"reason": "예약이 승인되었습니다",
"changedAt": "2024-06-07T13:00:00Z",
"changedBy": "business"
}
],
"canModify": true,
"canCancel": true,
"cancelDeadline": "2024-06-14T14:00:00Z",
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T13:00:00Z"
}
}
4. 예약 수정
예약 정보를 수정합니다.
Request
Request Syntax
curl -X PUT https://{SERVER_URL}/api/reservations/{reservationId} \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"reservationDate": "2024-06-16",
"reservationTime": "15:00",
"notes": "앞머리와 옆머리 모두 짧게 잘라주세요",
"reason": "일정 변경으로 인한 수정"
}'
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
reservationDate | string | N | 변경할 예약 날짜 | 2024-06-16 | YYYY-MM-DD 형식 |
reservationTime | string | N | 변경할 예약 시간 | 15:00 | HH:mm 형식 |
notes | string | N | 변경할 요청사항 | 앞머리와... | 500자 이하 |
reason | string | Y | 수정 사유 | 일정 변경으로... | 100자 이하 |
Response
Response Syntax (200 OK)
예약 상세 조회와 동일한 응답 구조를 반환합니다.
5. 예약 취소
예약을 취소합니다.
Request
Request Syntax
curl -X DELETE https://{SERVER_URL}/api/reservations/{reservationId} \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"reason": "개인 사정으로 인한 취소"
}'
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
reason | string | Y | 취소 사유 | 개인 사정으로... | 100자 이하 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약이 취소되었습니다",
"data": {
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"previousStatus": "CONFIRMED",
"currentStatus": "CANCELLED",
"reason": "개인 사정으로 인한 취소",
"cancelledAt": "2024-06-07T14:00:00Z"
}
}
6. 받은 예약 신청 조회 (업체용)
업체가 받은 예약 신청을 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/reservations?status=PENDING&date=2024-06-15 \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/businesses/{businessId}/reservations |
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4... |
Query Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 | 기본값 |
---|---|---|---|---|---|
status | string | N | 예약 상태 필터 | PENDING, CONFIRMED | 전체 |
date | string | N | 특정 날짜 필터 | 2024-06-15 | 오늘 |
startDate | string | N | 조회 시작 날짜 | 2024-06-01 | 7일 전 |
endDate | string | N | 조회 종료 날짜 | 2024-06-30 | 30일 후 |
page | integer | N | 페이지 번호 | 1 | 1 |
size | integer | N | 페이지 크기 | 10 | 20 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약 목록 조회가 완료되었습니다",
"data": {
"businessInfo": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실"
},
"reservations": [
{
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"reservationNumber": "RES-20240615-001",
"status": "PENDING",
"customerInfo": {
"customerId": "440e8400-e29b-41d4-a716-446655440006",
"customerName": "김고객",
"customerPhone": "01098765432",
"profileImageUrl": "<https://example.com/profile.jpg>"
},
"reservationDetails": {
"date": "2024-06-15",
"time": "14:00",
"durationMinutes": 60,
"selectedOptions": [
{
"optionName": "커트",
"price": 25000
}
],
"totalPrice": 25000,
"notes": "앞머리 짧게 잘라주세요"
},
"createdAt": "2024-06-07T12:30:00Z",
"requiresAction": true
}
],
"pagination": {
"currentPage": 1,
"totalPages": 3,
"totalElements": 25,
"size": 10,
"hasNext": true,
"hasPrevious": false
},
"summary": {
"totalToday": 8,
"pendingCount": 3,
"confirmedCount": 5,
"totalRevenue": 200000
}
}
}
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
BUSINESS_NOT_FOUND | 404 | "업체 정보를 찾을 수 없습니다" | 존재하지 않는 업체 |
ACCESS_DENIED | 403 | "접근 권한이 없습니다" | 업체 구성원이 아님 |
VALIDATION_ERROR | 400 | "입력값이 올바르지 않습니다" | 파라미터 검증 실패 |
7. 예약 승인/거절 (업체용)
예약 신청을 승인하거나 거절합니다.
Request
Request Syntax
curl -X PATCH https://{SERVER_URL}/api/businesses/{businessId}/reservations/{reservationId}/status \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"status": "CONFIRMED",
"reason": "예약이 승인되었습니다"
}'
메서드 | 요청 URL |
---|---|
PATCH | https://{SERVER_URL}/api/businesses/{businessId}/reservations/{reservationId}/status |
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4... |
reservationId | string | Y | 예약 ID (UUID) | 990e8400-e29b-41d4... |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
status | string | Y | 변경할 상태 | CONFIRMED, CANCELLED |
reason | string | N | 승인/거절 사유 | 예약이 승인되었습니다 |
예약 상태 값
값 | 설명 |
---|---|
CONFIRMED | 승인됨 |
CANCELLED | 거절됨 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약이 승인되었습니다",
"data": {
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"previousStatus": "PENDING",
"currentStatus": "CONFIRMED",
"reason": "예약이 승인되었습니다",
"updatedAt": "2024-06-07T13:00:00Z",
"updatedBy": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"name": "홍길동",
"role": "OWNER"
}
}
}
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
RESERVATION_NOT_FOUND | 404 | "예약 정보를 찾을 수 없습니다" | 존재하지 않는 예약 |
RESERVATION_INVALID_STATUS | 400 | "현재 예약 상태에서는 처리할 수 없습니다" | 상태 변경 불가 |
ACCESS_DENIED | 403 | "접근 권한이 없습니다" | 업체 구성원이 아님 |
INSUFFICIENT_PERMISSION | 403 | "해당 작업을 수행할 권한이 없습니다" | MEMBER 역할 제한 |
8. 예약 상태 변경 - 완료/노쇼 (업체용)
예약을 완료 또는 노쇼 처리합니다.
Request
Request Syntax
curl -X PATCH https://{SERVER_URL}/api/businesses/{businessId}/reservations/{reservationId}/complete \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"status": "COMPLETED",
"notes": "서비스가 정상적으로 완료되었습니다"
}'
메서드 | 요청 URL |
---|---|
PATCH | https://{SERVER_URL}/api/businesses/{businessId}/reservations/{reservationId}/complete |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
status | string | Y | 완료 상태 | COMPLETED, NO_SHOW |
notes | string | N | 완료 메모 | 서비스가 정상적으로... |
완료 상태 값
값 | 설명 |
---|---|
COMPLETED | 서비스 완료 |
NO_SHOW | 고객 노쇼 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약이 완료 처리되었습니다",
"data": {
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"previousStatus": "CONFIRMED",
"currentStatus": "COMPLETED",
"notes": "서비스가 정상적으로 완료되었습니다",
"completedAt": "2024-06-15T15:00:00Z",
"completedBy": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"name": "홍길동",
"role": "OWNER"
}
}
}
9. 예약 캘린더 조회 (업체용)
업체의 예약 현황을 캘린더 형태로 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/reservations/calendar?year=2024&month=6 \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/businesses/{businessId}/reservations/calendar |
Query Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 | 기본값 |
---|---|---|---|---|---|
year | integer | N | 조회 연도 | 2024 | 현재 연도 |
month | integer | N | 조회 월 | 6 | 현재 월 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약 캘린더 조회가 완료되었습니다",
"data": {
"businessInfo": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실"
},
"calendar": {
"year": 2024,
"month": 6,
"days": [
{
"date": "2024-06-15",
"dayOfWeek": 6,
"isBusinessDay": true,
"businessHours": {
"openTime": "09:00",
"closeTime": "18:00"
},
"reservations": [
{
"reservationId": "990e8400-e29b-41d4-a716-446655440004",
"time": "14:00",
"duration": 60,
"status": "CONFIRMED",
"customerName": "김고객",
"serviceName": "커트",
"price": 25000
}
],
"totalReservations": 5,
"totalRevenue": 125000,
"availableSlots": 8
}
],
"monthSummary": {
"totalReservations": 150,
"totalRevenue": 3750000,
"averageDaily": 5,
"busyDays": ["2024-06-15", "2024-06-22", "2024-06-29"]
}
}
}
}
10. 업체 조회 (고객용)
고객이 예약하고자 하는 업체 정보를 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/public \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/businesses/{businessId}/public |
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4... |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "업체 정보 조회가 완료되었습니다",
"data": {
"businessInfo": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"businessType": "미용실",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678",
"description": "깔끔하고 세련된 미용실입니다",
"logoUrl": "<https://example.com/logo.jpg>",
"rating": 4.8,
"reviewCount": 127
},
"businessHours": [
{
"dayOfWeek": 1,
"dayName": "월요일",
"openTime": "09:00",
"closeTime": "18:00",
"isClosed": false
},
{
"dayOfWeek": 0,
"dayName": "일요일",
"openTime": null,
"closeTime": null,
"isClosed": true
}
],
"services": [
{
"serviceId": "aa0e8400-e29b-41d4-a716-446655440005",
"serviceName": "기본 커트",
"description": "기본적인 헤어커트 서비스입니다",
"price": 25000,
"duration": 60,
"category": "기본",
"imageUrl": "<https://example.com/cut.jpg>"
}
],
"policies": {
"cancelDeadlineHours": 24,
"modifyDeadlineHours": 24,
"advanceBookingDays": 30
}
}
}
권한 체계 및 변경사항
업체 예약 관리 권한
역할 | 예약 조회 | 예약 승인/거절 | 예약 완료/노쇼 | 캘린더 조회 |
---|---|---|---|---|
OWNER | ✅ | ✅ | ✅ | ✅ |
MANAGER | ✅ | ✅ | ✅ | ✅ |
MEMBER | ✅ | ❌ | ❌ | ✅ |
권한 체크 로직 변경사항
기존 방식
-- 기존: business.user_id 기반 소유권 체크
SELECT b.* FROM business b
WHERE b.id = ? AND b.user_id = ?
신규 방식
-- 신규: user_business_role 테이블 기반 권한 체크
SELECT ubr.role FROM user_business_role ubr
WHERE ubr.user_id = ?
AND ubr.business_id = ?
AND ubr.is_active = true
API URL 변경사항
기존 | 신규 | 변경사항 |
---|---|---|
/api/business/reservations | /api/businesses/{businessId}/reservations | businessId 기반 |
사용자 기준 조회 | 비즈니스별 조회 | 명확한 리소스 구분 |
예약 상태 관리
예약 상태 전이도
PENDING → CONFIRMED → COMPLETED
↓ ↓
CANCELLED CANCELLED
↓ ↓
X NO_SHOW
상태별 가능한 액션
현재 상태 | 고객 가능 액션 | 업체 가능 액션 |
---|---|---|
PENDING | 수정, 취소 | 승인, 거절 |
CONFIRMED | 취소 | 완료, 노쇼, 취소 |
COMPLETED | - | - |
CANCELLED | - | - |
NO_SHOW | - | - |
예약 정책
항목 | 기본값 | 설명 |
---|---|---|
취소 데드라인 | 24시간 전 | 예약 시간 24시간 전까지 취소 가능 |
수정 데드라인 | 24시간 전 | 예약 시간 24시간 전까지 수정 가능 |
선예약 기간 | 30일 | 최대 30일 후까지 예약 가능 |
당일 예약 | 2시간 전 | 예약 시간 2시간 전까지 당일 예약 가능 |
에러 코드 정의
예약 관련 에러
에러 코드 | HTTP Status | 메시지 | 발생 상황 |
---|---|---|---|
RESERVATION_NOT_FOUND | 404 | "예약 정보를 찾을 수 없습니다" | 존재하지 않는 예약 |
RESERVATION_INVALID_STATUS | 400 | "현재 예약 상태에서는 처리할 수 없습니다" | 상태 변경 불가 |
RESERVATION_DEADLINE_PASSED | 400 | "예약 변경/취소 가능 시간이 지났습니다" | 데드라인 초과 |
SLOT_NOT_AVAILABLE | 409 | "해당 시간대는 예약할 수 없습니다" | 슬롯 예약 불가 |
SLOT_ALREADY_BOOKED | 409 | "이미 예약된 시간대입니다" | 슬롯 중복 예약 |
BUSINESS_CLOSED | 400 | "해당 날짜는 영업일이 아닙니다" | 영업시간 외 예약 |
SERVICE_NOT_AVAILABLE | 400 | "선택하신 서비스는 현재 이용할 수 없습니다" | 비활성화된 서비스 |
권한 관련 에러
에러 코드 | HTTP Status | 메시지 | 발생 상황 |
---|---|---|---|
ACCESS_DENIED | 403 | "접근 권한이 없습니다" | 기본 권한 부족 |
INSUFFICIENT_PERMISSION | 403 | "해당 작업을 수행할 권한이 없습니다" | 역할별 권한 부족 |
NOT_BUSINESS_MEMBER | 403 | "해당 업체의 구성원이 아닙니다" | 업체 구성원 아님 |
NOT_RESERVATION_OWNER | 403 | "본인의 예약이 아닙니다" | 예약 소유권 없음 |
알림 및 이벤트
예약 관련 알림 이벤트
이벤트 | 고객 알림 | 업체 알림 | 알림 내용 |
---|---|---|---|
예약 신청 | ✅ 신청 완료 | ✅ 새 예약 신청 | 예약번호, 날짜/시간, 서비스 |
예약 승인 | ✅ 예약 확정 | - | 확정 안내, 업체 연락처 |
예약 거절 | ✅ 예약 거절 | - | 거절 사유, 대안 제시 |
예약 수정 | ✅ 수정 완료 | ✅ 예약 변경 | 변경 내용, 사유 |
예약 취소 | ✅ 취소 완료 | ✅ 예약 취소 | 취소 사유, 환불 정보 |
예약 완료 | ✅ 서비스 완료 | - | 리뷰 요청, 재방문 유도 |
예약 리마인더 | ✅ 1일 전, 1시간 전 | ✅ 당일 일정 | 준비사항, 주의사항 |
데이터 무결성 및 비즈니스 규칙
예약 검증 규칙
- 시간 중복 방지: 동일 시간대에 슬롯 용량 초과 예약 방지
- 영업시간 검증: 업체 영업시간 내에서만 예약 가능
- 과거 날짜 방지: 현재 시간 이후로만 예약 가능
- 서비스 유효성: 활성화된 서비스만 예약 가능
- 데드라인 검증: 취소/수정 데드라인 준수